package com.rockymew.core.spring.exceptionhandler;



import java.lang.reflect.Field;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import com.rockymew.core.exception.BusinessCoreException;
import com.rockymew.core.wsresult.WsResult;

/**
 * 异常的统一处理  返回错误页面或者JSON
 * @author zln
 *
 */
public class UnifyExceptionHandlerExceptionResolver extends ExceptionHandlerExceptionResolver{
    @SuppressWarnings("unused")
    private Logger logger = LoggerFactory.getLogger( this.getClass() );
    
    @Resource RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    
    @Override
    public void afterPropertiesSet() {
        //设置消息转换器 以及内容协商管理器
        Field cnm = ReflectionUtils.findField(RequestMappingHandlerAdapter.class, "contentNegotiationManager");
        cnm.setAccessible(true);
        setContentNegotiationManager( (ContentNegotiationManager) ReflectionUtils.getField(cnm, requestMappingHandlerAdapter) );
        setMessageConverters( requestMappingHandlerAdapter.getMessageConverters() );
        
        super.afterPropertiesSet();
    }
    
    /**
     * 重写 {@code doResolveHandlerMethodException} 以便支持 @ExceptionHandler
     */
    @Override
    protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod,
            Exception exception) {
        ModelAndView mv = null;
        
        mv =  super.doResolveHandlerMethodException(request, response, handlerMethod, exception);
        if( null != mv ){
            return mv;
        }
        
        if( null != handlerMethod.getMethodAnnotation(ResponseBody.class) ){
            mv = doResolveResponseBodyHandlerMehtod(request, response, handlerMethod, exception);
            
            if( null != mv ){
                return mv;
            }
        }
        
        return doFallbackResolveHandlerMethodException( request, response, handlerMethod, exception );
    }
    
    protected ModelAndView doFallbackResolveHandlerMethodException( HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod,
            Exception exception ){
        
        ModelAndView oops = new ModelAndView();
        oops.setViewName("oops");
        
        return oops;
    }
    
    protected ModelAndView doResolveResponseBodyHandlerMehtod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod,
            Exception exception) {
        try {
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            
            WsResult wsResult = null;
            if( exception instanceof BusinessCoreException ){
                wsResult = ((BusinessCoreException)exception).toWsResult();
            }else{
                wsResult = WsResult.failed( exception.getMessage() );
            }

            this.getReturnValueHandlers().handleReturnValue(wsResult, handlerMethod.getReturnValueType(wsResult), mavContainer,
                    webRequest);

            if (mavContainer.isRequestHandled()) {
                return new ModelAndView();
            } else {
/*              ModelAndView mav = new ModelAndView().addAllObjects(mavContainer.getModel());
                mav.setViewName(mavContainer.getViewName());
                if (!mavContainer.isViewReference()) {
                    mav.setView((View) mavContainer.getView());
                }
                return mav;*/
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }
    
}
